﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Xml.Highlightings;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.Psi.Xml;
using JetBrains.ReSharper.Psi.Xml.Tree;
using SPCAFContrib.Entities.Consts;
using SPCAFContrib.ReSharper.Common;
using SPCAFContrib.ReSharper.Common.Attributes;
using SPCAFContrib.ReSharper.Common.Extensions;
using SPCAFContrib.ReSharper.Common.Psi.XmlCache;
using SPCAFContrib.ReSharper.Common.Solution.ProjectFileCache;
using SPCAFContrib.ReSharper.Common.XmlAnalysis;
using SPCAFContrib.ReSharper.Consts;
using SPCAFContrib.ReSharper.Inspection.Xml;

[assembly: RegisterConfigurableSeverity(WrongFeatureIdInListInstanceHighlighting.CheckId,
  null,
  Consts.SPCAF_CORRECTNESS_GROUP,
  WrongFeatureIdInListInstanceHighlighting.CheckId + ": " + WrongFeatureIdInListInstanceHighlighting.Message,
  "It is important to remember to add the right FeatureId attribute to the ListInstance element, if the TemplateType attribute points to a list template which is not in the same feature as the one you are creating the list instance in. If you forget or set it wrong (copy&paste), you will get some very vague error messages.",
  Severity.ERROR,
  false, Internal = false)]

namespace SPCAFContrib.ReSharper.Inspection.Xml
{
    [Applicability(
        IDEProjectType.SP2010FarmSolution |
        IDEProjectType.SPSandbox |
        IDEProjectType.SP2013FarmSolution)]
    public class WrongFeatureIdInListInstance : XmlTagProblemAnalyzer
    {
        public override void Run(IXmlTag element, IHighlightingConsumer consumer)
        {
            if (element.GetProject().IsApplicableFor(this))
            {
                if (IsInvalid(element))
                {
                    IXmlAttribute attribute = element.GetAttribute("FeatureId");
                    WrongFeatureIdInListInstanceHighlighting errorHighlighting =
                        new WrongFeatureIdInListInstanceHighlighting(attribute);
                    consumer.ConsumeHighlighting(attribute.GetDocumentRange(), errorHighlighting);
                }
            }
        }

        public static bool IsInvalid(IXmlTag element)
        {
            bool result = false;

            if (element.Header.ContainerName == "ListInstance")
            {
                var solution = element.GetSolution();
                IXmlAttribute featureId = element.GetAttribute("FeatureId");
                Guid templateFeatureId = Guid.Empty;

                if (featureId != null && !String.IsNullOrEmpty(featureId.UnquotedValue) &&
                    Guid.TryParse(featureId.UnquotedValue, out templateFeatureId))
                {
                    FeatureXmlEntity featureOfListTemplate = FeatureCache.GetInstance(solution)
                        .Items.SingleOrDefault(
                            f => f.Id.Equals(templateFeatureId));
                        
                    result = featureOfListTemplate == null;

                    if (featureOfListTemplate != null && element.AttributeExists("TemplateType"))
                    {
                        IXmlAttribute templateType = element.GetAttribute("TemplateType");
                        if (!String.IsNullOrEmpty(templateType.UnquotedValue))
                        {
                            int templateId = Int32.Parse(templateType.UnquotedValue);
                            var listTemplate = ListTemplateCache.GetInstance(solution)
                                .Items.FirstOrDefault(lt => Int32.Parse(lt.Type) == templateId);

                            if (listTemplate != null && !String.IsNullOrEmpty(listTemplate.SourceFileFullPath))
                            {
                                var sourceFilePath = listTemplate.SourceFileFullPath;
                                var project = element.GetProject();
                                var solutionComponent = solution.GetComponent<SharePointProjectItemsSolutionProvider>();
                                IEnumerable<SharePointProjectItem> spProjectItems =
                                    solutionComponent.GetCacheContent(project);
                                var projectItem =
                                    spProjectItems.SingleOrDefault(
                                        pi =>
                                            pi.ItemType == SharePointProjectItemType.ListDefinition &&
                                            pi.ElementManifest == listTemplate.SourceFileName &&
                                            pi.Path == sourceFilePath);
                                if (projectItem != null)
                                {
                                    FeatureXmlEntity feature = FeatureCache.GetInstance(solution)
                                        .Items.SingleOrDefault(
                                            f => f.ProjectItems.Any(pi => pi.Equals(projectItem.Id)));

                                    result = feature != null && featureOfListTemplate.Id != feature.Id;
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }
    }

    [ConfigurableSeverityHighlighting(CheckId, XmlLanguage.Name, OverlapResolve = OverlapResolveKind.NONE, ShowToolTipInStatusBar = true)]
    public class WrongFeatureIdInListInstanceHighlighting : XmlErrorHighlighting
    {
        public const string CheckId = CheckIDs.Rules.ListInstance.WrongFeatureIdInListInstance;
        public const string Message = "Wrong FeatureId for list instance";

        public IXmlAttribute Element { get; private set; }

        public WrongFeatureIdInListInstanceHighlighting(IXmlAttribute element) :
            base(String.Format("{0}: {1}", CheckId, Message))
        {
            Element = element;
        }

        public override bool IsValid()
        {
            return this.Element.IsValid();
        }
    }
}
